﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;

namespace FinalPointSet.Model.Util
{
    /// <summary>
    /// 热键
    /// </summary>
    public static class HotKeyUtil
    {

        #region API
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool RegisterHotKey(IntPtr hWnd, int id, HotkeyModifiers fsModifiers, uint vk);

        [DllImport("user32.dll")]
        static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        #endregion

        /// <summary>
        /// 注册快捷键
        /// </summary>
        /// <param name="window">持有快捷键窗口</param>
        /// <param name="fsModifiers">组合键</param>
        /// <param name="key">快捷键</param>
        /// <param name="callBack">回调函数</param>
        public static bool Regist(Window window, HotkeyModifiers fsModifiers, Key key, HotKeyCallBackHanlder callBack)
        {
            var hwnd = new WindowInteropHelper(window).Handle;
            if((int)hwnd == 0)
                return false;
            var _hwndSource = HwndSource.FromHwnd(hwnd);
            _hwndSource.AddHook(WndProc);

            int id = keyid++;

            var vk = KeyInterop.VirtualKeyFromKey(key);
            if (!RegisterHotKey(hwnd, id, fsModifiers, (uint)vk))
            {
                Debug.Print("regist hotkey fail.");
                return false;
            }
            keymap[id] = callBack;
            return true;
        }

        /// <summary>
        /// 快捷键消息处理
        /// </summary>
        static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_HOTKEY)
            {
                int id = wParam.ToInt32();
                if (keymap.TryGetValue(id, out var callback))
                {
                    callback();
                }
            }
            return IntPtr.Zero;
        }

        /// <summary>
        /// 注销快捷键
        /// </summary>
        /// <param name="hWnd">持有快捷键窗口的句柄</param>
        /// <param name="callBack">回调函数</param>
        public static void UnRegist(IntPtr hWnd, HotKeyCallBackHanlder callBack)
        {
            foreach (KeyValuePair<int, HotKeyCallBackHanlder> var in keymap)
            {
                if (var.Value == callBack)
                    UnregisterHotKey(hWnd, var.Key);
            }

        }

        /// <summary>
        /// 判断按键是否特殊按键(Ctrl、Shift、Alt)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsSpecialKey(Key key)
        {
            return IsCtrl(key) || IsShift(key) || IsAlt(key);
        }

        /// <summary>
        /// 判断key是否为Ctrl键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsCtrl(Key key)
        {
            return key == Key.LeftCtrl || key == Key.RightCtrl;
        }

        /// <summary>
        /// 判断key是否为Shift键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsShift(Key key)
        {
            return key == Key.LeftShift || key == Key.RightShift;
        }

        /// <summary>
        /// 判断key是否为Alt键
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsAlt(Key key)
        {
            return key == Key.LeftAlt || key == Key.RightAlt;
        }

        public static bool CanBeSetting(Key key)
        {
            return HotKeyMapping.Keys.Any(k => k.Key == key);
        }
        public static string GetKeyName(Key key)
        {
            HotKey matchKey = HotKeyMapping.Keys[key];
            if (matchKey != null)
            {
                return matchKey.Name;
            }
            return "";
        }
        public static Key GetKeyCode(string keyName)
        {
            List<HotKey> hotkeys = HotKeyMapping.Keys.Values.ToList();
            return hotkeys.FirstOrDefault(k => k.Name.Equals(keyName), new HotKey()).Key;
        }

        public static HotKey GetHotKey(Key key)
        {
            return HotKeyMapping.Keys[key];
        }

        public static List<HotKey> GetHotKeys(List<Key> keys)
        {
            List<HotKey> list_keys = new();
            foreach (Key item in keys)
            {
                list_keys.Add(GetHotKey(item));
            }
            return list_keys;
        }

        /// <summary>
        /// 获取快捷键的名称
        /// </summary>
        /// <param name="normalKey">普通键</param>
        /// <param name="specialKeys">特殊键</param>
        /// <returns></returns>
        public static string GetHotKeyCombinationName(Key normalKey, List<Key> specialKeys)
        {
            if (normalKey == Key.None)
            {
                return "";
            }
            List<string> results = new();
            bool isContainCtrl = false, isContainShift = false, isContainAlt = false;
            foreach (Key key in specialKeys)
            {
                if (IsCtrl(key))
                {
                    isContainCtrl = true;
                }
                else if (IsShift(key))
                {
                    isContainShift = true;
                }
                else if (IsAlt(key))
                {
                    isContainAlt = true;
                }
            }
            if (isContainCtrl)
            {
                results.Add("Ctrl");
            }
            if (isContainShift)
            {
                results.Add("Shift");
            }
            if (isContainAlt)
            {
                results.Add("Alt");
            }
            if (normalKey != Key.None)
            {
                results.Add(GetKeyName(normalKey));
            }

            return string.Join('+', results);

        }
        const int WM_HOTKEY = 0x312;
        static int keyid = 10;
        private static Dictionary<int, HotKeyCallBackHanlder> keymap = new();

        public delegate void HotKeyCallBackHanlder();
    }

    public enum HotkeyModifiers
    {
        Alt = 0x1,
        Ctrl = 0x2,
        Shift = 0x4,
        None = 0x0
        //Win = 0x8
    }

    public enum RegistResult
    {
        /// <summary>
        /// 成功
        /// </summary>
        Success,
        /// <summary>
        /// 警告
        /// </summary>
        Warn,
        /// <summary>
        /// 错误
        /// </summary>
        Error,
        /// <summary>
        /// 无
        /// </summary>
        None
    }
    public class HotKey
    {
        public HotKey() { }
        public HotKey(Key key, string name)
        {
            Key = key;
            Name = name;
        }
        [JsonIgnore]
        public Key Key { get; set; } = Key.None;
        public string Name { get; set; } = string.Empty;

        public override string? ToString()
        {
            return $"Name={Name}, Key={Key}";
        }
    }

    /// <summary>
    /// 快捷键值
    /// </summary>
    public class HotKeyMapping
    {
        public static Dictionary<Key, HotKey> Keys = new Dictionary<Key, HotKey> {
        {Key.Escape, new HotKey(Key.Escape,"Esc")},
        {Key.F1, new HotKey(Key.F1,"F1" )},
        {Key.F2, new HotKey(Key.F2,"F2")},
        {Key.F3, new HotKey(Key.F3,"F3")},
        {Key.F4, new HotKey(Key.F4,"F4")},
        {Key.F5, new HotKey(Key.F5,"F5")},
        {Key.F6, new HotKey(Key.F6,"F6")},
        {Key.F7, new HotKey(Key.F7,"F7")},
        {Key.F8, new HotKey(Key.F8,"F8")},
        {Key.F9, new HotKey(Key.F9,"F9")},
        {Key.F10, new HotKey(Key.F10,"F10")},
        {Key.F11, new HotKey(Key.F11,"F11")},
        {Key.F12, new HotKey(Key.F12,"F12")},
        {Key.D0, new HotKey(Key.D0,"0")},
        {Key.D1, new HotKey(Key.D1,"1")},
        {Key.D2, new HotKey(Key.D2,"2")},
        {Key.D3, new HotKey(Key.D3,"3")},
        {Key.D4, new HotKey(Key.D4,"4")},
        {Key.D5, new HotKey(Key.D5,"5")},
        {Key.D6, new HotKey(Key.D6,"6")},
        {Key.D7, new HotKey(Key.D7,"7")},
        {Key.D8, new HotKey(Key.D8,"8")},
        {Key.D9, new HotKey(Key.D9,"9")},
        {Key.OemMinus,new HotKey(Key.OemMinus ,"-")},
        {Key.OemPlus,new HotKey(Key.OemPlus ,"+")},
        {Key.Back, new HotKey(Key.Back,"Back")},
        {Key.Tab, new HotKey(Key.Tab,"Tab")},
        {Key.Q, new HotKey(Key.Q,"Q")},
        {Key.W, new HotKey(Key.W,"W")},
        {Key.E, new HotKey(Key.E,"E")},
        {Key.R, new HotKey(Key.R,"R")},
        {Key.T, new HotKey(Key.T,"T")},
        {Key.Y, new HotKey(Key.Y,"Y")},
        {Key.U, new HotKey(Key.U,"U")},
        {Key.I, new HotKey(Key.I,"I")},
        {Key.O, new HotKey(Key.O,"O")},
        {Key.P, new HotKey(Key.P,"P")},
        {Key.CapsLock, new HotKey(Key.CapsLock,"CapsLock")},
        {Key.A, new HotKey(Key.A,"A")},
        {Key.S, new HotKey(Key.S,"S")},
        {Key.D, new HotKey(Key.D,"D")},
        {Key.F, new HotKey(Key.F,"F")},
        {Key.G, new HotKey(Key.G,"G")},
        {Key.H, new HotKey(Key.H,"H")},
        {Key.J, new HotKey(Key.J,"J")},
        {Key.K, new HotKey(Key.K,"K")},
        {Key.L, new HotKey(Key.L,"L")},
        {Key.Return, new HotKey(Key.Return,"Enter")},
        {Key.LeftShift, new HotKey(Key.LeftShift,"Shift")},
        {Key.Z, new HotKey(Key.Z,"Z")},
        {Key.X, new HotKey(Key.X,"X")},
        {Key.C, new HotKey(Key.C,"C")},
        {Key.V, new HotKey(Key.V,"V")},
        {Key.B, new HotKey(Key.B,"B")},
        {Key.N, new HotKey(Key.N,"N")},
        {Key.M, new HotKey(Key.M,"M")},
        {Key.RightShift, new HotKey(Key.RightShift,"Shift")},
        {Key.LeftCtrl, new HotKey(Key.LeftCtrl,"Ctrl")},
        {Key.LeftAlt, new HotKey(Key.LeftAlt,"Alt")},
        {Key.Space, new HotKey(Key.Space,"Space")},
        {Key.RightAlt, new HotKey(Key.RightAlt,"Alt")},
        {Key.RightCtrl, new HotKey(Key.RightCtrl,"Ctrl")},
        {Key.Up,new HotKey(Key.Up ,"↑")},
        {Key.Down,new HotKey(Key.Down ,"↓")},
        {Key.Left,new HotKey(Key.Left ,"←")},
        {Key.Right,new HotKey(Key.Right ,"→")},
        {Key.NumPad0, new HotKey(Key.NumPad0,"Num0")},
        {Key.NumPad1, new HotKey(Key.NumPad1,"Num1")},
        {Key.NumPad2, new HotKey(Key.NumPad2,"Num2")},
        {Key.NumPad3, new HotKey(Key.NumPad3,"Num3")},
        {Key.NumPad4, new HotKey(Key.NumPad4,"Num4")},
        {Key.NumPad5, new HotKey(Key.NumPad5,"Num5")},
        {Key.NumPad6, new HotKey(Key.NumPad6,"Num6")},
        {Key.NumPad7, new HotKey(Key.NumPad7,"Num7")},
        {Key.NumPad8, new HotKey(Key.NumPad8,"Num8")},
        {Key.NumPad9, new HotKey(Key.NumPad9,"Num9")},
        {Key.None, new HotKey(Key.None,"None")}
    };
    }


    public class HotKeyCombination
    {
        /// <summary>
        /// 快捷键组合的名称
        /// </summary>
        public string Name { get; set; } = string.Empty;
        /// <summary>
        /// 普通按键
        /// </summary>
        public HotKey NormalKey { get; set; } = new HotKey();
        /// <summary>
        /// 特殊按键
        /// </summary>
        public List<HotKey> SpecialKeys { get; set; } = new();

        /// <summary>
        /// 注册状态
        /// </summary>
        [JsonIgnore]
        public RegistResult RegistResult { get; set; } = RegistResult.Error;
        /// <summary>
        /// 设置快捷键的按键数量
        /// </summary>
        [JsonIgnore]
        public int Count { get; set; } = 0;
        public HotKeyCombination() { }
        public override string? ToString()
        {
            return $"Name={Name}, NormalKey: {NormalKey}, SpecialKeys: {string.Join('|', SpecialKeys)}";
        }
    }
}